﻿using System;
using System.Configuration;
using System.Messaging;
using System.ServiceProcess;
using System.Threading;

namespace JCE.ARB
{
	class ARBProgram : ServiceBase
	{
		protected static bool IsService { get; set; }
		protected static Mutex SingleInstanceMutex { get; set; }

		private static void Main(string[] args)
		{
			IsService = !Environment.UserInteractive;
			AppDomain.CurrentDomain.ProcessExit += CurrentDomain_ProcessExit;

			if (IsService)
			{
				ServiceBase.Run(new ARBProgram());
			}
			else
			{
				ARBProgram service = new ARBProgram();
				service.StartService(args);
				service.MessageThread.Join();
			}
		}

		private static void CurrentDomain_ProcessExit(object sender, EventArgs e)
		{
			if (GlobalState.ARBQueue != null)
			{
				GlobalState.ARBQueue.Close();
			}

			if (SingleInstanceMutex != null)
			{
				SingleInstanceMutex.Dispose();
			}
		}

		protected Thread MessageThread { get; set; }

		public ARBProgram()
		{
			CanStop = true;
			CanPauseAndContinue = true;
			CanShutdown = true;
			ServiceName = string.Format(LocalizedStrings.ServiceName, GlobalState.InstanceName);
			AutoLog = false;

			SingleInstanceMutex = new Mutex(false, string.Format(LocalizedStrings.SingleIntanceMutexName, GlobalState.InstanceName));
		}

		public void StartService(string[] args)
		{
			OnStart(args);
		}

		public void StopService()
		{
			OnStop();
		}

		public void PauseService()
		{
			OnPause();
		}

		public void ContinueService()
		{
			OnContinue();
		}

		protected override void OnStart(string[] args)
		{
			base.OnStart(args);

			LogMessage("OnStart");
			GlobalState.IsRunning = SingleInstanceMutex.WaitOne(TimeSpan.FromSeconds(3), false);

			if (!GlobalState.IsRunning)
			{
				Console.WriteLine(LocalizedStrings.MultipleInstanceMessage);
				GlobalState.ARBQueue.Send(new Message(ARBMessageType.StopService, GlobalState.ARBQueueFormatter));
			}

			GlobalState.HasStopped = false;
			GlobalState.IsPaused = false;
			MessageThread = new Thread(new ParameterizedThreadStart(ProcessMessages));
			MessageThread.Start(args);
		}

		protected override void OnStop()
		{
			base.OnStop();

			LogMessage("OnStop");
			GlobalState.ARBQueue.Send(new Message(ARBMessageType.StopService, GlobalState.ARBQueueFormatter));
		}

		protected override void OnPause()
		{
			base.OnPause();

			LogMessage("OnPause");
			GlobalState.ARBQueue.Send(new Message(ARBMessageType.PauseService, GlobalState.ARBQueueFormatter));
		}

		protected override void OnContinue()
		{
			base.OnContinue();

			LogMessage("OnContinue");
			GlobalState.ARBQueue.Send(new Message(ARBMessageType.ContinueService, GlobalState.ARBQueueFormatter));
		}

		protected override void OnShutdown()
		{
			base.OnShutdown();

			LogMessage("OnShutdown");
			GlobalState.ARBQueue.Send(new Message(ARBMessageType.ShutdownService, GlobalState.ARBQueueFormatter));
		}

		protected void ProcessMessages(object argsObject)
		{
			LogMessage("ProcessMessages");

			string[] args = argsObject as string[];
			foreach (string arg in args)
			{
				LogMessage(arg);
			}

			while (!GlobalState.HasStopped)
			{
				LogMessage("Waiting on message queue...");
				using (Message message = GlobalState.ARBQueue.Receive())
				{
					message.Formatter = GlobalState.ARBQueueFormatter;
					ARBMessageType messageBody = (ARBMessageType)message.Body;
					LogMessage(string.Format("Processing message: {0}", messageBody));

					switch(messageBody)
					{
						case ARBMessageType.StopService:
						case ARBMessageType.ShutdownService:
							GlobalState.HasStopped = true;
							break;
						case ARBMessageType.PauseService:
							GlobalState.IsPaused = true;
							break;
						case ARBMessageType.ContinueService:
							GlobalState.IsPaused = false;
							break;
						default:
							throw new InvalidOperationException(string.Format(LocalizedStrings.UnrecognizedMessageString, messageBody));
					}
				}
			}
		}

		protected void LogMessage(string message)
		{
			if (IsService)
			{
				EventLog.WriteEntry(message);
			}
			else
			{
				Console.WriteLine(message);
			}
		}
	}
}
